package org.cybzacg.encryption.factory;

import org.cybzacg.encryption.core.Encryptor;
import org.cybzacg.encryption.impl.SM2Encryptor;
import org.cybzacg.encryption.impl.SM4Encryptor;
import org.cybzacg.encryption.enums.NationalAlgorithm;
import org.cybzacg.encryption.enums.EncryptionAlgorithm;
import org.cybzacg.encryption.context.EncryptionContext;
import org.cybzacg.encryption.model.EncryptionResult;
import org.cybzacg.encryption.model.ValidationResult;
import org.cybzacg.encryption.utils.ValidationUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.security.KeyPair;
import java.util.function.Function;

/**
 * 国密算法工厂
 * 提供国密算法的统一创建和管理功能
 * 
 * @author encryption team
 * @version 1.0
 */
public class NationalAlgorithmFactory {
    
    private static final NationalAlgorithmFactory INSTANCE = new NationalAlgorithmFactory();
    
    // 国密算法缓存
    private final Map<NationalAlgorithm, Encryptor> encryptorCache = new ConcurrentHashMap<>();
    
    // 统计信息
    private final AtomicLong totalCreations = new AtomicLong(0);
    private final AtomicLong cacheHits = new AtomicLong(0);
    private final AtomicLong cacheMisses = new AtomicLong(0);
    
    // 配置
    private volatile boolean cachingEnabled = true;
    private volatile int maxCacheSize = 100;
    
    /**
     * 私有构造函数
     */
    private NationalAlgorithmFactory() {
        // 预初始化常用算法
        initializeCache();
    }
    
    /**
     * 获取工厂实例
     * 
     * @return 工厂实例
     */
    public static NationalAlgorithmFactory getInstance() {
        return INSTANCE;
    }
    
    /**
     * 创建国密算法加密器
     * 
     * @param algorithm 国密算法
     * @return 加密器实例
     */
    public Encryptor createEncryptor(NationalAlgorithm algorithm) {
        if (algorithm == null) {
            throw new IllegalArgumentException("National algorithm cannot be null");
        }
        
        // 检查缓存
        if (cachingEnabled) {
            Encryptor cached = encryptorCache.get(algorithm);
            if (cached != null) {
                cacheHits.incrementAndGet();
                return cached;
            }
            cacheMisses.incrementAndGet();
        }
        
        // 创建新的加密器
        Encryptor encryptor = createNewEncryptor(algorithm);
        totalCreations.incrementAndGet();
        
        // 添加到缓存
        if (cachingEnabled && encryptorCache.size() < maxCacheSize) {
            encryptorCache.put(algorithm, encryptor);
        }
        
        return encryptor;
    }
    
    /**
     * 从加密算法创建国密算法加密器
     * 
     * @param algorithm 加密算法
     * @return 加密器实例
     */
    public Encryptor createEncryptor(EncryptionAlgorithm algorithm) {
        NationalAlgorithm nationalAlgorithm = mapToNationalAlgorithm(algorithm);
        if (nationalAlgorithm == null) {
            throw new IllegalArgumentException("Unsupported encryption algorithm for national algorithms: " + algorithm);
        }
        return createEncryptor(nationalAlgorithm);
    }
    
    /**
     * 创建SM2加密器
     * 
     * @return SM2加密器实例
     */
    public SM2Encryptor createSM2Encryptor() {
        return (SM2Encryptor) createEncryptor(NationalAlgorithm.SM2);
    }
    
    /**
     * 创建SM3工具类实例
     * 
     * @return SM3工具类包装器
     */
    public SM3Wrapper createSM3Wrapper() {
        return new SM3Wrapper();
    }
    
    /**
     * 创建SM4加密器
     * 
     * @return SM4加密器实例
     */
    public SM4Encryptor createSM4Encryptor() {
        return (SM4Encryptor) createEncryptor(NationalAlgorithm.SM4);
    }
    
    /**
     * 批量创建加密器
     * 
     * @param algorithms 国密算法数组
     * @return 加密器映射
     */
    public Map<NationalAlgorithm, Encryptor> createEncryptors(NationalAlgorithm... algorithms) {
        Map<NationalAlgorithm, Encryptor> result = new ConcurrentHashMap<>();
        for (NationalAlgorithm algorithm : algorithms) {
            result.put(algorithm, createEncryptor(algorithm));
        }
        return result;
    }
    
    /**
     * 创建所有国密算法加密器
     * 
     * @return 所有国密算法加密器映射
     */
    public Map<NationalAlgorithm, Encryptor> createAllEncryptors() {
        return createEncryptors(NationalAlgorithm.values());
    }
    
    /**
     * 检查算法是否支持
     * 
     * @param algorithm 国密算法
     * @return 是否支持
     */
    public boolean isSupported(NationalAlgorithm algorithm) {
        return algorithm != null && mapToEncryptorClass(algorithm) != null;
    }
    
    /**
     * 检查加密算法是否为国密算法
     * 
     * @param algorithm 加密算法
     * @return 是否为国密算法
     */
    public boolean isNationalAlgorithm(EncryptionAlgorithm algorithm) {
        return mapToNationalAlgorithm(algorithm) != null;
    }
    
    /**
     * 获取所有支持的国密算法
     * 
     * @return 支持的国密算法数组
     */
    public NationalAlgorithm[] getSupportedAlgorithms() {
        return NationalAlgorithm.values();
    }
    
    /**
     * 生成国密算法密钥对
     * 
     * @param algorithm 国密算法
     * @return 密钥对
     * @throws Exception 生成异常
     */
    public KeyPair generateKeyPair(NationalAlgorithm algorithm) throws Exception {
        switch (algorithm) {
            case SM2:
                return SM2Encryptor.generateKeyPair();
            case SM3:
                throw new UnsupportedOperationException("SM3 is a hash algorithm, does not support key pair generation");
            case SM4:
                throw new UnsupportedOperationException("SM4 is a symmetric algorithm, does not support key pair generation");
            default:
                throw new UnsupportedOperationException("Unsupported national algorithm: " + algorithm);
        }
    }
    
    /**
     * 验证国密算法配置
     * 
     * @param algorithm 国密算法
     * @param context 加密上下文
     * @return 验证结果
     */
    public ValidationResult validateConfiguration(NationalAlgorithm algorithm, EncryptionContext context) {
        if (algorithm == null) {
            return new ValidationResult.Builder()
                    .valid(false)
                    .message("National algorithm cannot be null")
                    .build();
        }
        
        if (context == null) {
            return new ValidationResult.Builder()
                    .valid(false)
                    .message("Encryption context cannot be null")
                    .build();
        }
        
        // 检查算法匹配
        EncryptionAlgorithm expectedAlgorithm = mapToEncryptionAlgorithm(algorithm);
        if (expectedAlgorithm != context.getAlgorithm()) {
            return new ValidationResult.Builder()
                    .valid(false)
                    .message(String.format("Algorithm mismatch: expected %s, got %s", 
                        expectedAlgorithm, context.getAlgorithm()))
                    .build();
        }
        
        // 算法特定验证
        try {
            Encryptor encryptor = createEncryptor(algorithm);
            return encryptor.validate(context);
        } catch (Exception e) {
            return new ValidationResult.Builder()
                    .valid(false)
                    .message("Configuration validation failed: " + e.getMessage())
                    .build();
        }
    }
    
    /**
     * 清空缓存
     */
    public void clearCache() {
        encryptorCache.clear();
    }
    
    /**
     * 启用/禁用缓存
     * 
     * @param enabled 是否启用缓存
     */
    public void setCachingEnabled(boolean enabled) {
        this.cachingEnabled = enabled;
        if (!enabled) {
            clearCache();
        }
    }
    
    /**
     * 检查缓存是否启用
     * 
     * @return 是否启用缓存
     */
    public boolean isCachingEnabled() {
        return cachingEnabled;
    }
    
    /**
     * 设置最大缓存大小
     * 
     * @param maxSize 最大缓存大小
     */
    public void setMaxCacheSize(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("Max cache size must be positive");
        }
        this.maxCacheSize = maxSize;
        
        // 如果当前缓存超过限制，清空缓存
        if (encryptorCache.size() > maxSize) {
            clearCache();
        }
    }
    
    /**
     * 获取最大缓存大小
     * 
     * @return 最大缓存大小
     */
    public int getMaxCacheSize() {
        return maxCacheSize;
    }
    
    /**
     * 获取工厂统计信息
     * 
     * @return 统计信息
     */
    public FactoryStatistics getStatistics() {
        return new FactoryStatistics(
            totalCreations.get(),
            cacheHits.get(),
            cacheMisses.get(),
            encryptorCache.size(),
            maxCacheSize,
            cachingEnabled
        );
    }
    
    /**
     * 重置统计信息
     */
    public void resetStatistics() {
        totalCreations.set(0);
        cacheHits.set(0);
        cacheMisses.set(0);
    }
    
    /**
     * 预初始化缓存
     */
    private void initializeCache() {
        try {
            // 预创建常用算法的加密器
            createEncryptor(NationalAlgorithm.SM2);
            createEncryptor(NationalAlgorithm.SM4);
        } catch (Exception e) {
            // 预初始化失败，不影响正常使用
        }
    }
    
    /**
     * 创建新的加密器实例
     * 
     * @param algorithm 国密算法
     * @return 加密器实例
     */
    private Encryptor createNewEncryptor(NationalAlgorithm algorithm) {
        Class<? extends Encryptor> encryptorClass = mapToEncryptorClass(algorithm);
        if (encryptorClass == null) {
            throw new IllegalArgumentException("Unsupported national algorithm: " + algorithm);
        }
        
        try {
            return encryptorClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Failed to create encryptor for algorithm " + algorithm, e);
        }
    }
    
    /**
     * 将国密算法映射到加密器类
     * 
     * @param algorithm 国密算法
     * @return 加密器类
     */
    private Class<? extends Encryptor> mapToEncryptorClass(NationalAlgorithm algorithm) {
        switch (algorithm) {
            case SM2:
                return SM2Encryptor.class;
            case SM4:
                return SM4Encryptor.class;
            default:
                return null;
        }
    }
    
    /**
     * 将国密算法映射到加密算法
     * 
     * @param algorithm 国密算法
     * @return 加密算法
     */
    private EncryptionAlgorithm mapToEncryptionAlgorithm(NationalAlgorithm algorithm) {
        switch (algorithm) {
            case SM2:
                return EncryptionAlgorithm.SM2;
            case SM4:
                return EncryptionAlgorithm.SM4;
            default:
                return null;
        }
    }
    
    /**
     * 将加密算法映射到国密算法
     * 
     * @param algorithm 加密算法
     * @return 国密算法
     */
    private NationalAlgorithm mapToNationalAlgorithm(EncryptionAlgorithm algorithm) {
        switch (algorithm) {
            case SM2:
                return NationalAlgorithm.SM2;
            case SM4:
                return NationalAlgorithm.SM4;
            default:
                return null;
        }
    }
    
    /**
     * SM3工具类包装器
     */
    public static class SM3Wrapper {
        
        /**
         * 计算SM3哈希值
         * 
         * @param data 输入数据
         * @return SM3哈希值
         * @throws Exception 计算异常
         */
        public byte[] hash(byte[] data) throws Exception {
            return org.cybzacg.encryption.utils.SM3Utils.hash(data);
        }
        
        /**
         * 计算SM3哈希值（字符串）
         * 
         * @param data 输入字符串
         * @return SM3哈希值
         * @throws Exception 计算异常
         */
        public byte[] hash(String data) throws Exception {
            return org.cybzacg.encryption.utils.SM3Utils.hash(data);
        }
        
        /**
         * 计算SM3哈希值（十六进制）
         * 
         * @param data 输入数据
         * @return SM3哈希值的十六进制字符串
         * @throws Exception 计算异常
         */
        public String hashToHex(byte[] data) throws Exception {
            return org.cybzacg.encryption.utils.SM3Utils.hashToHex(data);
        }
        
        /**
         * 计算SM3 HMAC值
         * 
         * @param data 输入数据
         * @param key 密钥
         * @return SM3 HMAC值
         * @throws Exception 计算异常
         */
        public byte[] hmac(byte[] data, byte[] key) throws Exception {
            return org.cybzacg.encryption.utils.SM3Utils.hmac(data, key);
        }
        
        /**
         * 验证SM3哈希值
         * 
         * @param data 原始数据
         * @param expectedHash 期望的哈希值
         * @return 验证结果
         */
        public boolean verifyHash(byte[] data, byte[] expectedHash) {
            return org.cybzacg.encryption.utils.SM3Utils.verifyHash(data, expectedHash).isValid();
        }
        
        /**
         * 验证SM3 HMAC值
         * 
         * @param data 原始数据
         * @param key 密钥
         * @param expectedHMAC 期望的HMAC值
         * @return 验证结果
         */
        public boolean verifyHMAC(byte[] data, byte[] key, byte[] expectedHMAC) {
            return org.cybzacg.encryption.utils.SM3Utils.verifyHMAC(data, key, expectedHMAC).isValid();
        }
        
        /**
         * 检查SM3算法是否可用
         * 
         * @return 是否可用
         */
        public boolean isAvailable() {
            return org.cybzacg.encryption.utils.SM3Utils.isAvailable();
        }
        
        /**
         * 获取算法信息
         * 
         * @return 算法信息
         */
        public String getAlgorithmInfo() {
            return org.cybzacg.encryption.utils.SM3Utils.getAlgorithmInfo();
        }
        
        /**
         * 获取统计信息
         * 
         * @return 统计信息
         */
        public String getStatistics() {
            return org.cybzacg.encryption.utils.SM3Utils.getStatistics();
        }
        
        /**
         * 重置统计信息
         */
        public void resetStatistics() {
            org.cybzacg.encryption.utils.SM3Utils.resetStatistics();
        }
    }
    
    /**
     * 国密算法构建器
     */
    public static class Builder {
        
        private boolean cachingEnabled = true;
        private int maxCacheSize = 100;
        private Map<NationalAlgorithm, Function<NationalAlgorithm, Encryptor>> customCreators = new ConcurrentHashMap<>();
        
        /**
         * 设置缓存启用状态
         * 
         * @param enabled 是否启用缓存
         * @return 当前构建器实例
         */
        public Builder setCachingEnabled(boolean enabled) {
            this.cachingEnabled = enabled;
            return this;
        }
        
        /**
         * 设置最大缓存大小
         * 
         * @param maxSize 最大缓存大小
         * @return 当前构建器实例
         */
        public Builder setMaxCacheSize(int maxSize) {
            this.maxCacheSize = maxSize;
            return this;
        }
        
        /**
         * 注册自定义创建器
         * 
         * @param algorithm 国密算法
         * @param creator 创建器函数
         * @return 当前构建器实例
         */
        public Builder registerCreator(NationalAlgorithm algorithm, Function<NationalAlgorithm, Encryptor> creator) {
            customCreators.put(algorithm, creator);
            return this;
        }
        
        /**
         * 构建国密算法工厂
         * 
         * @return 国密算法工厂实例
         */
        public NationalAlgorithmFactory build() {
            NationalAlgorithmFactory factory = getInstance();
            factory.setCachingEnabled(cachingEnabled);
            factory.setMaxCacheSize(maxCacheSize);
            return factory;
        }
    }
    
    /**
     * 工厂统计信息
     */
    public static class FactoryStatistics {
        
        private final long totalCreations;
        private final long cacheHits;
        private final long cacheMisses;
        private final int cacheSize;
        private final int maxCacheSize;
        private final boolean cachingEnabled;
        
        public FactoryStatistics(long totalCreations, long cacheHits, long cacheMisses,
                                int cacheSize, int maxCacheSize, boolean cachingEnabled) {
            this.totalCreations = totalCreations;
            this.cacheHits = cacheHits;
            this.cacheMisses = cacheMisses;
            this.cacheSize = cacheSize;
            this.maxCacheSize = maxCacheSize;
            this.cachingEnabled = cachingEnabled;
        }
        
        public long getTotalCreations() {
            return totalCreations;
        }
        
        public long getCacheHits() {
            return cacheHits;
        }
        
        public long getCacheMisses() {
            return cacheMisses;
        }
        
        public int getCacheSize() {
            return cacheSize;
        }
        
        public int getMaxCacheSize() {
            return maxCacheSize;
        }
        
        public boolean isCachingEnabled() {
            return cachingEnabled;
        }
        
        public double getCacheHitRate() {
            long totalRequests = cacheHits + cacheMisses;
            return totalRequests > 0 ? (double) cacheHits / totalRequests : 0.0;
        }
        
        @Override
        public String toString() {
            return String.format(
                "NationalAlgorithmFactory Statistics:\n" +
                "  Total Creations: %d\n" +
                "  Cache Hits: %d\n" +
                "  Cache Misses: %d\n" +
                "  Cache Hit Rate: %.2f%%\n" +
                "  Cache Size: %d/%d\n" +
                "  Caching Enabled: %s",
                totalCreations, cacheHits, cacheMisses, getCacheHitRate() * 100,
                cacheSize, maxCacheSize, cachingEnabled
            );
        }
    }
}
